using System;
using System.Collections.Generic;
using System.Threading;
using System.Text;

using System.Drawing;
using System.Windows.Forms;

namespace Weazel.Gezel.Simulator.Reference.IpBlocks
{
  [IpBlockAttribute("pongdisplay")]
  public class PongDisplayBlock : AbstractIpBlock
  {

    private const int BallXPinNumber = 0;
    private const int BallYPinNumber = 1;		
  
    private const int LeftPaddleXPinNumber = 2;
    private const int LeftPaddleYPinNumber = 3;
    private const int RightPaddleXPinNumber = 4;
    private const int RightPaddleYPinNumber = 5;


    private int fieldHeight = -1;
    private int fieldWidth = -1;
    
    PongDisplayControl displayControl;

    public PongDisplayBlock(string name)
      : base(name)
    {      
    }

    private void RunThread()
    {
      Form form = new Form();

      displayControl = new PongDisplayControl();
      displayControl.Dock = DockStyle.Fill;
      

      form.Controls.Add(displayControl);
      form.ActiveControl = displayControl;
      form.ClientSize = new Size(fieldWidth, fieldHeight);

      form.ShowDialog();
    }

    /// <summary>
    /// Note, if parameters are not integers, or negative, 
    /// simulation will not run properly. It is hard to proper
    /// validation of ipblocks with the current lack of design 
    /// anyways.
    /// </summary>
    /// <param name="_name"></param>
    public override void SetParameter(string _name)
    {
      string field = _name.Substring(0, _name.IndexOf('='));
      string value = _name.Substring(_name.IndexOf('=') + 1);

      if (field == "width")
        fieldWidth = int.Parse(value);
      else if (field == "height")
        fieldHeight = int.Parse(value);

      if (fieldHeight != -1 && fieldWidth != -1)
      {
        Thread worker = new Thread(new ThreadStart(RunThread));
        worker.IsBackground = true;
        worker.Start();
      }
    }

    public override bool CheckTerminal(int n, string tname, IoDirection dir)
    {
      switch (n)
      {
        case 0:
          return (dir == AbstractIpBlock.IoDirection.Input && tname == "ball_x");
        case 1:
          return (dir == AbstractIpBlock.IoDirection.Input && tname == "ball_y");
        case 2:
          return (dir == AbstractIpBlock.IoDirection.Input && tname == "left_paddle_x");
        case 3:
          return (dir == AbstractIpBlock.IoDirection.Input && tname == "left_paddle_y");
        case 4:
          return (dir == AbstractIpBlock.IoDirection.Input && tname == "right_paddle_x");
        case 5:
          return (dir == AbstractIpBlock.IoDirection.Input && tname == "right_paddle_y");

        default:
          throw new NotSupportedException("CheckTerminal() unknown 'n' value");
      }
    }

    public override void Run()
    {
      try
      {        
        int ballX = ioValues[BallXPinNumber].ToInt();
        int ballY = ioValues[BallYPinNumber].ToInt();
        int leftPaddleX = ioValues[LeftPaddleXPinNumber].ToInt();
        int leftPaddleY = ioValues[LeftPaddleYPinNumber].ToInt();
        int rightPaddleX = ioValues[RightPaddleXPinNumber].ToInt();
        int rightPaddleY = ioValues[RightPaddleYPinNumber].ToInt();

        displayControl.Update(ballX, ballY, leftPaddleX, leftPaddleY, rightPaddleX, rightPaddleY);

        System.Threading.Thread.Sleep(20);

        //Console.WriteLine("ball position ({0}, {1})", ballX, ballY);
      }
      catch (Exception e)
      {
        String message = e.GetType().ToString() + " " +
          e.Message + " trace: \n" + e.StackTrace;

        System.Windows.Forms.MessageBox.Show(message);
      }
    }
  }


  public class PongDisplayControl : Control
  {
    private const int fieldHeight = 75;
    private const int fieldWidth = 100;
    private const int padding = 10;
    private const int ballDiameter = 1;
    private const int paddleHeight = 5;
    private const int paddleWidth = 1;

    int ballX, ballY, leftPaddleX, leftPaddleY, rightPaddleX, rightPaddleY;

    public PongDisplayControl()
    {
      SetStyle(ControlStyles.UserPaint, true);
    }

    public void Update(int ballX, int ballY, int leftPaddleX, int leftPaddleY, int rightPaddleX, int rightPaddleY)
    {
      this.ballX = ballX;
      this.ballY = ballY;
      this.leftPaddleX = leftPaddleX;
      this.leftPaddleY = leftPaddleY;
      this.rightPaddleX = rightPaddleX;
      this.rightPaddleY = rightPaddleY;
      this.Invalidate(ClientRectangle);

			//System.Diagnostics.Trace.Assert(this.ClientRectangle.Height == 75 && this.ClientRectangle.Width == 100);
    }

    protected override void OnPaintBackground(PaintEventArgs pevent)
    {
      pevent.Graphics.FillRectangle(Brushes.Black, ClientRectangle);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
      e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
      e.Graphics.FillEllipse(Brushes.Red, ballX, ballY	, ballDiameter, ballDiameter);
      e.Graphics.DrawEllipse(Pens.White, ballX, ballY, ballDiameter, ballDiameter);

      e.Graphics.FillRectangle(Brushes.White, leftPaddleX - paddleWidth, leftPaddleY, paddleWidth, paddleHeight);

      e.Graphics.FillRectangle(Brushes.White, rightPaddleX, rightPaddleY, paddleWidth, paddleHeight);
    }
  }
}

